/* 
 * File:   tf.c
 * Author: Tomás R. González Barroso  
 * Diseño de sistemas Operativos
 * Created on 26 de junio de 2013, 8:46
 */
#include "tf.h"
#include <sys/shm.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

//Tabla de ficheros
filetable * tabla_ficheros;
// Semaforo para exclusión mutua ficheros
extern int semfid;

//Inicializamos buffer y alojamos en memoria compartida
int ft_init_memory(int getmemory) {
    
    key_t shkey;                //Identificador para memoria compartida 
    int id_memoria = -1;  
    
    shkey = ftok ("/bin/ls", SMEMKEYF);
    if (shkey==-1) {
        perror("Error generando clave para memoria compartida para tabla de ficheros");
        exit(1);
    }
    
   //Creamos memoria compartida o la obtenemos si ya está creada.
    if (getmemory) 
       id_memoria = shmget (shkey, sizeof(filetable) , 0777 | IPC_CREAT);
    else
       id_memoria = shmget (shkey, sizeof(filetable) , 0777);
    
    if (id_memoria == -1)
    {
        perror("Error obteniendo ID memoria compartida para tabla de ficheros");
        exit(1);
    }


    tabla_ficheros = (filetable *)shmat (id_memoria, (char *)0, 0);
    if (tabla_ficheros == NULL)
    {
        perror("Error obteniendo memoria compartida  para tabla de ficheros");
        exit(1);
    }
    
    if (getmemory) 
       printf("Tabla de ficheros alojada correctamente en memoria compartida. "
            "ID:%i\n",id_memoria);    
    else
       printf("Tabla de ficheros apuntada correctamente. "
            "ID:%i\n",id_memoria);    
    
    return id_memoria;
}

//Inicializamos valores de la tabla
void ft_init_data(void) {
    int i;
    
    
    tabla_ficheros -> n = 0;
    
    // initialize hash list
    for (i = 0; i < MAXFILES; i++) {
        tabla_ficheros ->files[i].tam = -1;            
        tabla_ficheros ->files[i].io = -1;        
        tabla_ficheros ->files[i].inode = -1;              
    }
   
        
}

//Visualizamos el tabla de ficheros
void tf_print (void) {
    int i;
        
    printf("Nº de ficheros en tabla de ficheros => %d \n" ,tabla_ficheros -> n);    
    //Visualizamos atributos de los ficheros
    for (i=0;i < MAXFILES;i++) {
        if (tabla_ficheros ->files[i].inode != -1) {
            printf("F(%i) => ",i);        
            printf("Perm(%d) ",tabla_ficheros ->files[i].permisos);        
            printf("Io(%d) ",(int) tabla_ficheros ->files[i].io);        
            printf("Inode(%d) ",(int) tabla_ficheros ->files[i].inode);        
            printf("Tam(%d) ",(int) tabla_ficheros ->files[i].tam);        
            printf("\n");            
        }
    }    
 }

void tf_free_mem (int id_memoria,int getmemory) {

    shmdt ((char *)tabla_ficheros);
    if (getmemory)
       shmctl (id_memoria, IPC_RMID, (struct shmid_ds *)NULL);
    printf("Tabla de ficheros liberada.\n");

}

//Añadimos un nuevo fichero a la tabla en exclusión mutua.
int tf_open(char *filepath,int mode) {
    int i;
    struct stat buf;
    
    //Activamos semaforo (rojo)
    while (!semWait(semfid)); 
    
   
    i = tabla_ficheros -> n;
    //Comprobamos si podemos añadir mas ficheros
    if (i == MAXFILES) {
        perror("Numero maximo de ficheros en TF. open\n");
        return -1;
    }   
    //Comprobamos permisos
    if (access(filepath, mode) == -1){        
        perror("Permisos fichero. access");
            if (!semSignal(semfid)) {
            perror("Error liberando semaforo ficheros. open");
            exit(1);
        }
        return -1;
    }
    if (stat(filepath, &buf) == -1){        
        perror("Acceso fichero. stat");
        if (!semSignal(semfid)) {
            perror("Error liberando semaforo ficheros. open");
            exit(1);
        }
        return -1;
    }
    printf("Agregando fichero a la tabla de ficheros.\n"); 
    //Buscamos primer hueco libre
    i = 0;
    while ((tabla_ficheros ->files[i].inode != -1) && (i< MAXFILES))
        i++;
    tabla_ficheros ->files[i].inode = buf.st_ino;
    tabla_ficheros ->files[i].tam = buf.st_size;
    tabla_ficheros ->files[i].io = 0;
    tabla_ficheros ->files[i].permisos = mode;
    tabla_ficheros -> n++;
    
    // Liberamos semaforo (verde otros procesos)
    if (!semSignal(semfid)) {
        perror("Error liberando semaforo ficheros. open");
        exit(1);
    }
    
    return i;
}

//Liberamos fichero 
void tf_close(int fd) {
    
    //Activamos semaforo (rojo)
    while (!semWait(semfid)); 
    
    printf("Eliminando fichero a la tabla.\n");    
    tabla_ficheros ->files[fd].tam = -1;            
    tabla_ficheros ->files[fd].io = -1;        
    tabla_ficheros ->files[fd].inode = -1;              
    
    tabla_ficheros ->n--;
    
    if (!semSignal(semfid)) {
        perror("Error liberando semaforo ficheros. open");
        exit(1);
    }
    
}

